package tsou.cn.threadtest;

import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class AsyncTaskActivity extends AppCompatActivity {

    /**
     * TextView
     */
    private TextView mTextView;
    private AsyncTask<String, Integer, StringBuilder> task;
    private ProgressDialog progressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async_task);
        initData();
        initView();
//        initExecute();
//        initExecuteOnExecutor();
        initMyExecute();
    }


    private void initData() {
        progressDialog = new ProgressDialog(AsyncTaskActivity.this);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setMessage("加载中...");
    }

    private void initView() {
        mTextView = (TextView) findViewById(R.id.textView);
    }

    /**
     * 默认AsyncTask.SERIAL_EXECUTOR
     * 2.3系统同时execute执行10个异步任务
     * 3.1版本之前的系统默认最大并发执行5个线程，缓冲线程队列最大128个。虽然开了10个异步任务，
     * 但是只能同时并发执行5个，其他的任务都得等前面5个执行完后才继续执行，接着也是5次并发执行。
     * <p>
     * 3.1版本之后系统，默认是使用SERIAL_EXECUTOR串行任务执行，
     * 可以预料到异步任务将会是一个个顺序执行
     * <p>
     * 一个个线程按加入顺序同步执行的。也就是说，线程池中只有一个核心线程在工作，
     * 其他线程都要等之前的线程执行完才能执行
     */
    private void initExecute() {
        String url = "http://blog.csdn.net/huangxiaoguo1";

        task = new MyAsyncTask().execute(url);
    }

    /**
     * 自定义线程池执行，仅支持3.1以上系统
     * <p>
     * 使用默认提供的AsyncTask.THREAD_POOL_EXECUTOR线程池
     * <p>
     * 最大并发执行5个线程，后面的线程都只能等之前5个结束之后再执行
     */
    private void initExecuteOnExecutor() {
        String url = "http://blog.csdn.net/huangxiaoguo1";
        task = new MyAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
    }

    /**
     * 自定义线程池,
     * <p>
     * 10个核心任务并发执行，而且缓存队列最多能够存储100个任务，
     * 当队列满了之后还可以创建10个运行线程
     * <p>
     * corePoolSize 核心线程池大小
     * maximumPoolSize 线程池最大容量大小
     * keepAliveTime 线程池空闲时，线程存活的时间
     * TimeUnit 时间单位
     * ThreadFactory 线程工厂
     * BlockingQueue任务队列
     * RejectedExecutionHandler 线程拒绝策略
     */
    private void initMyExecute() {
        String url = "http://blog.csdn.net/huangxiaoguo1";
        Executor myExecutor = new ThreadPoolExecutor(5, 50, 10,
                TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(100));

        //ExecutorService executorService = Executors.newFixedThreadPool(3);
        /**
         * myExecutor也可以为newCachedThreadPool，newFixedThreadPool，
         * newScheduledThreadPool，newSingleThreadExecutor
         */
        task = new MyAsyncTask().executeOnExecutor(myExecutor, url);
    }

    public class MyAsyncTask extends AsyncTask<String, Integer, StringBuilder> {

        /**
         * 在execute(Params... params)被调用后立即执行，
         * 一般用来在执行后台任务前对UI做一些标记。(准备工作)
         */
        @Override
        protected void onPreExecute() {
            //后台执行先回调
            super.onPreExecute();
            progressDialog.show();
        }

        /**
         * 在onPreExecute()完成后立即执行，用于执行较为费时的操作，
         * 此方法将接收输入参数和返回计算结果。
         * 在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。(主线程中执行
         *
         * @param strings
         * @return
         */
        @Override
        protected StringBuilder doInBackground(String... strings) {//对应第一个参数
            //后台处理操作，不能修改UI
            if (isCancelled())//Task被取消了，马上退出循环
                return null;
            try {
                URL url = new URL(strings[0]);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setReadTimeout(30000);
                conn.setConnectTimeout(30000);
                int code = conn.getResponseCode();
                if (code == 200) {
                    InputStream inputStream = conn.getInputStream();
                    InputStreamReader inputReader = new InputStreamReader(inputStream);
                    BufferedReader reader = new BufferedReader(inputReader);
                    StringBuilder stringBuilder = new StringBuilder();
                    while (true) {
                        String readLine = reader.readLine();
                        if (readLine != null) {
                            stringBuilder.append(readLine);
                        } else {
                            break;
                        }
                    }
                    reader.close();
                    inputReader.close();
                    conn.disconnect();
                    return stringBuilder;
                }

            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return null;//对应第三个参数
        }

        /**
         * 在调用publishProgress(Progress... values)时，此方法被执行，直接将进度信息更新到UI组件上。
         * (主线程中执行,当后台任务的执行进度发送改变时此方法会被调用).
         *
         * @param values
         */
        @Override
        protected void onProgressUpdate(Integer... values) {//对应第二个参数
            //后台任务,不能直接修改UI
            super.onProgressUpdate(values);
            if (isCancelled()) //Task被取消了，不再继续执行后面的代码
                return;
            progressDialog.setProgress(values[0]);

        }

        /**
         * 当后台操作结束时，此方法将会被调用，计算结果将做为参数传递到此方法中，
         * 直接将结果显示到UI组件上。(异步执行后这个方法被调用)
         *
         * @param s
         */
        @Override
        protected void onPostExecute(StringBuilder s) {//对应第三个参数
            //后台任务完成后回调，更新UI
            super.onPostExecute(s);
            if (isCancelled()) //Task被取消了，不再继续执行后面的代码
                return;
            progressDialog.dismiss();
            if (s != null)
                mTextView.setText(s);
        }

        @Override
        protected void onCancelled() {
            //取消时回调
            progressDialog.dismiss();
            super.onCancelled();
        }

//        @Override
//        protected void onCancelled(String s) {//对应第三个参数
//            super.onCancelled(s);
//        }
    }

    @Override
    protected void onDestroy() {
        //取消异步任务代码
        if (task != null && task.getStatus() == AsyncTask.Status.RUNNING) {
            task.cancel(true);
        }
        super.onDestroy();
    }
}
